import json
import random
import time
# import torch
import sys
import os

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from yanchengMJ import yanchengMJ_v5
from yanchengMJ import lib_MJ as tools


def get_op_card(index):
    '''
    通过编码找opcard 和副露情况
    '''

    index -= 36
    type = int(index / 21)
    dic = {0:[1,2,3], 1:[2,3,4], 2:[3,4,5], 3:[4,5,6], 4:[5,6,7], 5:[6,7,8], 6:[7,8,9]}

    t3 =  dic[int((index % 21) / 3)]
    card = dic[int((index % 21) / 3)][int((index % 21) % 3)]
    t3 = [t1 + 16 * type for t1 in t3]
    card = card + 16 * type

    # print(t3,card)
    return t3, card


def get_index_from_op_card(t3, card):
    """
    根据 t3 和 card 反向计算出 index。
    :param t3: 副露的三张牌列表，例如 [1, 2, 3]
    :param card: 实际操作的牌，例如 1
    :return: 对应的 index
    """
    type = int(card / 16)  # 获取牌的类型（0: 万，1: 条，2: 饼）

    t3_base = [t - 16 * type for t in t3]
    card_base = card - 16 * type

    dic = {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4, 5], 3: [4, 5, 6], 4: [5, 6, 7], 5: [6, 7, 8], 6: [7, 8, 9]}
    key = None
    for k, v in dic.items():
        if v == t3_base:
            key = k
            break

    # 确定位置
    pos = v.index(card_base)

    # 计算 index
    index = 36 + type * 21 + key * 3 + pos
    return index


def get_action_mask(op_card, cards=[], suits=[], canchi=False, self_turn=False):
    '''
    通过状态判断动作掩码
    :param op_card: 操作牌
    :param cards: 手牌
    :param suits: 副露
    :param canchi: 是否满足吃的条件
    :param self_turn: 是否自己回合
    :return: list--mask
    '''
    is_chi = False
    is_peng = False
    mask = [0]

    set_cards = list(set(cards))
    if self_turn:  # 自己回合，暗杠或补杠
        for card in set_cards:
            if cards.count(card) == 4:
                mask.append(tools.translate16_33(card) + 167)
        for suit in suits:
            if suit.count(suit[0]) == 3 and suit[0] in cards:
                mask.append(tools.translate16_33(suit[0]) + 201)
    else:
        if cards.count(op_card) == 3:  # 杠
            mask.append(tools.translate16_33(op_card) + 133)
        if cards.count(op_card) >= 2:
            mask.append(tools.translate16_33(op_card) + 99)

        if ((cards.count(op_card - 2) and cards.count(op_card - 1) or
             cards.count(op_card - 1) and cards.count(op_card + 1) or
             cards.count(op_card + 1) and cards.count(op_card + 2)
        ) and op_card < 48):
            is_chi = True and canchi

        if is_chi:
            if (cards.count(op_card - 2) and cards.count(op_card - 1)):
                mask.append(get_index_from_op_card([op_card - 2, op_card - 1, op_card], op_card))
            if (cards.count(op_card - 1) and cards.count(op_card + 1)):
                mask.append(get_index_from_op_card([op_card - 1, op_card, op_card + 1], op_card))
            if (cards.count(op_card + 1) and cards.count(op_card + 2)):
                mask.append(get_index_from_op_card([op_card, op_card + 1, op_card + 2], op_card))

    # print(mask)
    return mask


def get_action(data):
    pos = data["acting_seat_id"]
    # 先检查特殊操作（杠、碰等）
    if data["action_cards"][pos] is not None:
        if '4' in data["action_cards"][pos]:
            return 4, 0  # 杠操作返回整数0
        if '3' in data["action_cards"][pos]:
            return 3, data["action_cards"][pos]['3'][0][0]  # 直接返回整数
        if '5' in data["action_cards"][pos]:
            return 5, data["action_cards"][pos]['5'][0][0]  # 直接返回整数
        if '6' in data["action_cards"][pos]:
            return 6, data["action_cards"][pos]['6'][0][0]  # 直接返回整数
        if '9' in data["action_cards"][pos]:
            return 9, data["action_cards"][pos]['9'][0][0]  # 直接返回整数
            
    
    discards_op = [[], [], [], []]
    for i in range(4):
        # 处理 player_chi_cards
        if data["player_chi_cards_v2"][i]:
            discards_op[i].extend(sublist[1:] for sublist in data["player_chi_cards_v2"][i])
            
        
        # 处理 player_gang_cards
        if data["player_gang_cards_v2"][i]:
            discards_op[i].extend(sublist[1:] for sublist in data["player_gang_cards_v2"][i])
            
        
        # 处理 player_peng_cards
        if data["player_peng_cards_v2"][i]:
            discards_op[i].extend(sublist[1:] for sublist in data["player_peng_cards_v2"][i])
        print(discards_op)
            
        
        # 处理 player_bugang_cards
        if data["player_bugang_cards_v2"][i]:
            discards_op[i].extend(sublist[1:] for sublist in data["player_bugang_cards_v2"][i])
           
        
        # 处理 player_angang_cards
        if data["player_angang_cards_v2"][i]:
            discards_op[i].extend(sublist[1:] for sublist in data["player_angang_cards_v2"][i])
            
        
    
    #if len(data["player_chi_cards"]) == 4:
    #    for i in range(4):
    #        discards_op[i].extend(data["player_chi_cards"][i])
    #if len(data["player_peng_cards"]) == 4:
    #    for i in range(4):
    #        discards_op[i].extend(data["player_peng_cards"][i])
    #if len(data["player_gang_cards"]) == 4:
    #    for i in range(4):
    #        discards_op[i].extend(data["player_gang_cards"][i])
    #if len(data["player_bugang_cards"]) == 4:
    #    for i in range(4):
    #        discards_op[i].extend(data["player_bugang_cards"][i])
    #if len(data["player_angang_cards"]) == 4:
    #    for i in range(4):
    #        discards_op[i].extend(data["player_angang_cards"][i])

    # 检查是否有杠操作
    flag = False
    if data["action_cards"][pos] is not None:
        if '5' in data["action_cards"][pos].keys() or '6' in data["action_cards"][pos].keys():
            flag = True

    # 获取最后打出的牌 - 使用last_action字段更可靠
    opcard = None
    if data["last_action"]:
        opcard = data["last_action"][2]
    elif data["played_cards"][data["acting_seat_id"]]:
        opcard = data["played_cards"][data["acting_seat_id"]][-1]

    # 处理摸牌后打牌操作
    if data["action_cards"][pos] is not None and '7' in data["action_cards"][pos]:
        outcard = recommend_card(cards=data["player_hand_cards"][pos], suits=discards_op[pos],
                                baida_card=data["king_cards"][0], discards=data["played_cards"],
                                discards_op=discards_op, remain_num=len(data["remain_card_stack"]),
                                round=len(data["played_cards"][pos]), seat_id=pos,
                                hua_num=len(data["player_bu_cards"][pos]))
        # 返回整数而不是列表
        return 7, int(outcard)
    else:
        # 处理其他操作（碰、吃等）
        power = data["power_player_position"]
        canchi = pos == (power + 1) % 4
        
        if opcard is None:
            return 0, 0  # 返回整数0
        
        out_op = recommend_op(op_card=opcard, cards=data["player_hand_cards"][pos],
                             suits=discards_op[pos], baida_card=data["king_cards"][0],
                             discards=data["played_cards"], discards_op=discards_op,
                             canchi=canchi, self_turn=flag, isHu=False,
                             round=len(data["played_cards"][pos]),
                             hua_num=len(data["player_bu_cards"][pos]))
        
        print("out_op",out_op)
        if not out_op or len(out_op[0]) == 0:
            return 0, 0  # 返回整数0
        
        aa = out_op[0]
        act = 2  # 默认设置为碰操作
        if aa[0] != aa[1]:  # 吃操作
            act = 1
        
        # 返回关键牌而不是整个组合
        # 对于吃/碰操作，返回操作的目标牌（通常是别人打出的牌）
        return act, aa

def recommend_card(cards=[], suits=[],baida_card=None,  discards=[], discards_op=[],  remain_num=112,
                   round=0,seat_id=0,hua_num = 0):
    """
    功能：推荐出牌接口
    思路：使用向听数作为牌型选择依据，对最小ｘｔｓ的牌型，再调用相应的牌型类出牌决策
    :param cards: 手牌
    :param suits: 副露
    :param king_card: 宝牌
    :param discards: 弃牌
    :param discards_op: 场面副露
    :param fei_king: 飞宝数
    :param remain_num: 剩余牌
    :return: outCard 推荐出牌
    """
    # 打印所有输入参数
    print("======================================")
    print(f"seat_id:{seat_id}")
    print(f"Cards (手牌): {cards}")
    print(f"Discards (弃牌): {discards}")
    print(f"Discards_op (场面副露): {discards_op}")
    print("outcard")

    # data = {"state": {}, "mask": list(set([tools.translate16_33(card) + 2 for card in cards]))}
    # data["state"]["self_handcard"] = cards
    # data["state"]["self_chi"] = [suit for suit in suits if suit[0] != suit[1]]
    # data["state"]["self_peng_gang"] = [suit for suit in suits if suit[0] == suit[1]]
    # data["state"]["self_discard"] = discards[seat_id]
    # data["state"]["other_chi"] = [[suit for suit in discards_op[(seat_id + 1) % 4] if suit[0] != suit[1]],
    #                               [suit for suit in discards_op[(seat_id + 2) % 4] if suit[0] != suit[1]],
    #                               [suit for suit in discards_op[(seat_id + 3) % 4] if suit[0] != suit[1]]]
    # data["state"]["other_peng_gang"] = [[suit for suit in discards_op[(seat_id + 1) % 4] if suit[0] == suit[1]],
    #                                     [suit for suit in discards_op[(seat_id + 2) % 4] if suit[0] == suit[1]],
    #                                     [suit for suit in discards_op[(seat_id + 3) % 4] if suit[0] == suit[1]]]
    # data["state"]["other_discard"] = [discards[(seat_id + 1) % 4], discards[(seat_id + 2) % 4],discards[(seat_id + 3) % 4]]
    # data["state"]["other_hand"] = [[], [], []]
    # data["state"]["wall"] = []


    #
    # # print('data',data)
    # input = fe.state2obs(data)
    # # print("input",input)
    #
    # # model = _load_model("lss/checkpoint/99model.pt", 1)
    # logits, values = model(input)
    # action = logits.detach().cpu().numpy().flatten().argmax()
    # # print(action)
    # # print(tools.trans10to16(action - 2))
    #
    # outcard = tools.trans10to16(action - 2)
    # print("outcard1",outcard)

    # 使用 yanchengMJ_v5 模型进行推荐
    outcard = yanchengMJ_v5.recommend_card(cards=cards,suits=suits,baida_card=baida_card, discards=discards, discards_op=discards_op, seat_id=seat_id, remain_num = remain_num, round=round,hua_num=hua_num)

    # print("outcard2:", outcard)
    return outcard



def recommend_op(op_card, cards=[], suits=[], baida_card=None, discards=[], discards_op=[], canchi=False,
                 self_turn=False,  isHu=False, round=0, hua_num=0):
    """
    功能：动作决策接口
    思路：使用向听数作为牌型选择依据，对最小ｘｔｓ的牌型，再调用相应的牌型类动作决策
    :param op_card: 操作牌
    :param cards: 手牌
    :param suits: 副露
    :param king_card: 宝牌
    :param discards: 弃牌
    :param discards_op: 场面副露
    :param self_turn: 是否是自己回合
    :param canchi: 吃牌权限
    :param fei_king: 飞宝数
    :param isHu: 是否胡牌
    :return: [],isHu 动作组合牌，是否胡牌
    """
    # print("=====================================================")
    # print("canchi", canchi)
    # print("op_card", op_card)
    # print("cards", cards)
    # print("self_turn", self_turn)
    # print("suits", suits)
    # print("discards_op", discards_op)
    # print("king_card", king_card)
    # print("outop")

    if isHu:
        return [], isHu

    # data = {"state": {}, "mask": []}
    # data["state"]["self_handcard"] = cards
    # data["state"]["self_chi"] = [suit for suit in suits if suit[0] != suit[1]]
    # data["state"]["self_peng_gang"] = [suit for suit in suits if suit[0] == suit[1]]
    # data["state"]["self_discard"] = discards[seat_id]
    # data["state"]["other_chi"] = [[suit for suit in discards_op[(seat_id + 1) % 4] if suit[0] != suit[1]],
    #                               [suit for suit in discards_op[(seat_id + 2) % 4] if suit[0] != suit[1]],
    #                               [suit for suit in discards_op[(seat_id + 3) % 4] if suit[0] != suit[1]]]
    # data["state"]["other_peng_gang"] = [[suit for suit in discards_op[(seat_id + 1) % 4] if suit[0] == suit[1]],
    #                                     [suit for suit in discards_op[(seat_id + 2) % 4] if suit[0] == suit[1]],
    #                                     [suit for suit in discards_op[(seat_id + 3) % 4] if suit[0] == suit[1]]]
    # data["state"]["other_discard"] = [discards[(seat_id + 1) % 4], discards[(seat_id + 2) % 4],
    #                                   discards[(seat_id + 3) % 4]]
    # data["state"]["other_hand"] = [[], [], []]
    # data["state"]["wall"] = []
    # data["mask"] = get_action_mask(op_card, cards, suits, canchi, self_turn)
    # # print(data["mask"])
    #
    # input = fe.state2obs(data)
    # # print(input)
    # # model = _load_model("lss/checkpoint/99model.pt", 1)
    # logits, values = model(input)
    # action = logits.detach().cpu().numpy().flatten().argmax()
    # # print(action)
    # # print(tools.trans10to16(action - 2))

    out_op = []

    # if action == 0:
    #     return [], False
    # elif action == 1:
    #     return [], True
    # elif action >= 36 and action < 99:
    #     out_op = get_op_card(action)[0]
    # elif action >= 99 and action < 133:
    #     card = tools.trans10to16(action - 99)
    #     card = int(card)
    #     out_op = [card, card, card]
    # elif action >= 133 and action < 167:
    #     card = tools.trans10to16(action - 133)
    #     card = int(card)
    #     out_op = [card, card, card, card]
    # elif action >= 167 and action < 201:
    #     card = tools.trans10to16(action - 167)
    #     card = int(card)
    #     out_op = [card, card, card, card]
    # else:
    #     card = tools.trans10to16(action - 201)
    #     card = int(card)
    #     out_op = [card, card, card, card]
    #
    # for card in out_op:
    #     if card >= 48:
    return yanchengMJ_v5.recommend_op(op_card = op_card, cards=cards,suits=suits,baida_card=baida_card, discards=discards, discards_op=discards_op, canchi=canchi, self_turn=self_turn, isHu=isHu, round=round, hua_num=hua_num)
    return out_op, False


if __name__ == '__main__':
   # print(recommend_card(cards = [4, 6, 6, 9, 17, 20, 25, 33, 35, 36, 38], discards = [[20, 23], [20, 23], [25, 20], [24, 40]], discards_op = [[], [], [], []], baida_card=6))
   # state = 1
   #
   # canchi = True
   # op_card = 5
   # cards = [1,1,2,3,4,5,5,33,33,33,6]
   # self_turn = False
   # suits = []
   # discards_op = [[], [[3, 4, 5]], [], []]
   # dicards = [[7, 6], [25, 24], [25, 20], [24, 6]]
   # print(recommend_op(op_card = op_card, cards = cards, suits = suits, discards=
   # dicards, discards_op = discards_op, canchi = canchi, self_turn = self_turn, baida_card = 33,hua_num=3))

   data={'room_id': 255975, 'player_count': 4, 'acting_seat_id': 3, 'power_player_position': 0, 'played_cards': [[17, 8, 6, 41, 39], [33, 8, 25, 4], [24, 41, 5], [33, 19, 38]], 'player_hand_cards': [[2, 21, 22, 23, 24, 25, 25, 33, 34, 35], [2, 17, 18, 19, 19, 20, 21, 22, 23, 36, 36, 39, 40], [2, 7, 7, 18, 20, 22, 33, 34, 37, 38], [2, 4, 6, 18, 19, 36, 37, 38, 39, 39]], 'action_seq': [[0, 7, 17], [1, 7, 33], [2, 7, 1], [3, 3, 1], [3, 7, 33], [0, 7, 8], [1, 7, 8], [2, 7, 24], [3, 7, 9], [2, 2, 9], [2, 7, 41], [3, 7, 19], [0, 7, 6], [1, 7, 25], [2, 7, 40], [0, 2, 40], [0, 7, 41], [1, 7, 4], [2, 7, 5], [3, 7, 38], [0, 7, 39]], 'last_action': [0, 7, 39], 'player_chi_cards': [], 'player_peng_cards': [[2, 40, 40, 40], [3, 9, 9, 9]], 'player_gang_cards': [], 'player_bugang_cards': [], 'player_angang_cards': [], 'player_chi_cards_v2': [[], [], [], []], 'player_peng_cards_v2': [[[2, 40, 40, 40]], [], [[3, 9, 9, 9]], []], 'player_gang_cards_v2': [[], [], [], []], 'player_bugang_cards_v2': [[], [], [], []], 'player_angang_cards_v2': [[], [], [], []], 'player_bu_cards': [[], [], [], []], 'action_cards': [{}, {}, {}, {'2': [[39, 39, 39]]}], 'remain_card_stack': [3, 20, 34, 35, 3, 24, 41, 23, 9, 53, 7, 20, 5, 37, 21, 53, 5, 7, 17, 4, 35, 23, 3, 4, 53, 3, 37, 6, 6, 5, 18, 25, 53, 38, 17, 22, 24, 41, 8, 21, 8, 36, 35, 34], 'king_cards': [2]}
   get_action(data)


